#pragma once 
#include <bits/stdc++.h>

/*****************************************************************************
 *! @brief 我们给出一些使用类型萃取和可变参数模板的总和案例
 *  
 *  @link https://github.com/qicosmos/cosmos/tree/master/cpp11book @endlink
 * 
 * 
 * 
 *  
 ****************************************************************************/


//! 1. 使用C++11实现C++11的 std::optional类
template<typename T>
class Optional {
    // 提供一块足够容纳指定大小和对齐要求的对象的内存空间
    /**
     *! @brief std::aligned_storage能否分配大小足够、内存对齐的内存区域
     *!
     *!    尽管直接new 也能保证Struct内的成员在其类型上按字节对齐, 但还有
     *!    如下优势:
     * 
     *     1). 类型擦除和泛型编程：在同一块内存中构造不同类型的对象，例如在实现一些通用容器或泛型数据结构时。
     *     2). 优化内存分配：预先分配一大块内存并在其中逐个构造对象，可以减少内存分配和释放的开销，尤其在性能敏感的应用中。
     *     3). 自定义内存布局：在特定内存位置构造对象，例如在嵌入式系统或与硬件接口交互的场景中。
     */

    //!  通过这种方式创建的对象需要显式调用其析构函数释放
    using data_t = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
public:
    Optional(){}

    Optional(const T& v) {
        Create(v);
    }

    Optional(T&& v) {
        Create(std::move(v));
    }

    ~Optional() {
        Destroy();
    }

    Optional(const Optional& other) {
        if (other.IsInit())
            Assign(other);
    }

    Optional(Optional&& other) {
        if (other.IsInit()) {
            Assign(std::move(other));
            other.Destroy();
        }
    }

    Optional& operator=(Optional &&other) {
        Assign(std::move(other));
        return *this;
    }

    Optional& operator=(const Optional &other) {
        Assign(other);
        return *this;
    }

    template<class... Args>
    void emplace(Args&&... args) {
        Destroy();
        Create(std::forward<Args>(args)...);     //! 注意...的位置
    }

    bool IsInit() const { return m_hasInit; }

    explicit operator bool() const {
        return IsInit();
    }

    T& operator*() {
        return *((T*)(&m_data));
    }

    T const& operator*() const {
        if (IsInit()) {
            return *((T*)(&m_data));
        }

        throw std::exception("");
    }

    bool operator == (const Optional<T>& rhs) const
    {
        return (!bool(*this)) != (!rhs) ? false : (!bool(*this) ? true : (*(*this)) == (*rhs));
    }

    bool operator < (const Optional<T>& rhs) const {
        return !rhs ? false : (!bool(*this) ? true : (*(*this) < (*rhs)));
    }

    bool operator != (const Optional<T>& rhs) {
        return !(*this == (rhs));
    }

private:
    template<class... Args>
    void Create(Args&&... args) {
        new (&m_data) T(std::forward<Args>(args)...);
        m_hasInit = true;
    }

    void Destroy() {
        if (m_hasInit) {
            m_hasInit = false;
            ((T*)(&m_data))->~T();
        }
    }

    void Assign(const Optional& other) {
        if (other.IsInit()) {
            Copy(other.m_data);
            m_hasInit = true;
        } else {
            Destroy();
        }
    }

    void Assign(Optional&& other) {
        if (other.IsInit()) {
            Move(std::move(other.m_data));
            m_hasInit = true;
            other.Destroy();
        } else {
            Destroy();
        }
    }

    void Move(data_t&& val) {
        Destroy();
        new (&m_data) T(std::move(*((T*)(&val))));
    }

    void Copy(const data_t& val) {
        Destroy();
        new (&m_data) T(*((T*)(&val)));
    }

private:
    bool m_hasInit = false;
    data_t m_data;
};


struct Struct {
    Struct(int a, int b) : _a(a), _b(b) {}
    int _a, _b;
};


//! 2. 使用C++11实现惰性求值
namespace {
template<typename T>
struct Lazy{
public:
    Lazy() {}

    // 需要延迟执行的函数
    template<typename Func, typename... Args>
    Lazy(Func& f, Args&&... args) {
        // 按引用捕获
        // _func = [&f, &args...] { return f(args...); };  // v1
        _func = std::bind(f, std::forward<Args>(args)...); // v2
    }
public:
    // 延迟执行，将结果存放到optional中，下次不用重新计算直接获取结果
    T& value() {
        if (!_value.IsInit()) {
            _value = _func();
        }
        return *_value;
    }

    bool is_ok() const {
        return _value.IsInit();
    }
private:
    std::function<T()> _func;      //! lambda表达式可以捕获参数, 因此这里没有参数
    Optional<T>        _value;
};
} // namespcae

/**
 *! @brief 实现一个辅助函数，返回一个延迟运行某函数的对象
 * 
 * @tparam Func   将被延迟运行的函数的类型
 * @tparam Args   将被延迟运行的函数的参数的类型
 * @param  func   将被延迟运行的函数
 * @param  args   将被延迟运行的函数的参数
 * @return Lazy<typename std::result_of<Func(Args...)>::type> 延迟运行的函数的返回值类型
 */
template<typename Func, typename... Args>
Lazy<typename std::result_of<Func(Args...)>::type> lazy(Func&& func, Args&&... args) {
    return Lazy<typename std::result_of<Func(Args...)>::type>(
        std::forward<Func>(func), std::forward<Args>(args)...);
}


//! 3. 实现lambda表达式的链式调用
template<typename T>
class Task;

template<typename R, typename... Args>  // 函数的返回值和参数类型
class Task<R(Args...)> {
public:
    //! 传进来的是个临时值, 但是具名后期变成左值，因此使用std::move
    Task(std::function<R(Args...)>&& func) : _func(std::move(func)) {
        // std::cout << "===========here============" << std::endl;
    }  
    Task(std::function<R(Args...)>& func) : _func(func) {}
public:
    R run(Args&&... args) {
        auto ret =  _func(std::forward<Args>(args)...);
        std::cout << ret << std::endl;
        return ret;
    }

    template<typename Func>
    auto then(Func&& func) -> Task<typename std::result_of<Func(R)>::type(Args...)> {
        //! return_type表示func调用run的返回值的返回参数
        using return_type = typename std::result_of<Func(R)>::type;
        auto fn = std::move(_func);

        return Task<return_type(Args...)>([fn, &func](Args&&... args) {
            return func(fn(std::forward<Args>(args)...));
        });

        //! 保持原有的_func还在
        // return Task<return_type(Args...)>([this, &func](Args&&... args) {
        //     return func(this->_func(std::forward<Args>(args)...));
        // });
    }
private:
    std::function<R(Args...)> _func;
};

int comprehensive_apps();